/* p9_2: I2C to DS1307 multi-byte burst write */

/* This program communicate with the DS1307 Real-time Clock via I2C. The day (of the week), date, month and year are written using burst write. */
/* It sets the date to Monday Oct. 19th, 2009 */
/* 
  DS1307 parameters:
  fmax = 100 kHz */
/*  
  I2C1SCL PA6
  I2C1SDA PA7 */

#include "TM4C123GH6PM.h"

#define SLAVE_ADDR 0x68     /* 0110 1000 */

void I2C1_init(void);
char I2C1_burstWrite(int slaveAddr, char memAddr, int byteCount, char* data);

int main(void)
{
    char timeDateToSet[7] = {0x55, 0x58, 0x16, 0x01, 0x19, 0x10, 0x09};
    
    I2C1_init();

    /* use burst write to write day, date, month, and year */
    I2C1_burstWrite(SLAVE_ADDR, 3, 4, &timeDateToSet[3]);

    for (;;)
    {
    }
}

/* initialize I2C1 as master and the port pins */
void I2C1_init(void)
{
    SYSCTL->RCGCI2C |= 0x02;    /* enable clock to I2C1 */
    SYSCTL->RCGCGPIO |= 0x01;   /* enable clock to GPIOA */

    /* PORTA 7, 6 for I2C1 */
    GPIOA->AFSEL |= 0xC0;       /* PORTA 7, 6 for I2C1 */
    GPIOA->PCTL &= ~0xFF000000; /* PORTA 7, 6 for I2C1 */
    GPIOA->PCTL |= 0x33000000;
    GPIOA->DEN |= 0xC0;         /* PORTA 7, 6 as digital pins */
    GPIOA->ODR |= 0x80;         /* PORTA 7 as open drain */

    I2C1->MCR = 0x10;           /* master mode */
    I2C1->MTPR = 7;             /* 100 kHz @ 16 MHz */
}

/* This function is called by the startup assembly code to perform system specific initialization tasks. */
void SystemInit(void)
{
    /* Grant coprocessor access */
    /* This is required since TM4C123G has a floating point coprocessor */
    SCB->CPACR |= 0x00f00000;
}

/* Wait until I2C master is not busy and return error code */
/* If there is no error, return 0 */
static int I2C_wait_till_done(void)
{
    while(I2C1->MCS & 1);   /* wait until I2C master is not busy */
    return I2C1->MCS & 0xE; /* return I2C error code */
}

/* Use burst write to write multiple bytes to consecutive locations */
/* burst write: S-(saddr+w)-ACK-maddr-ACK-data-ACK-data-ACK-...-data-ACK-P */
char I2C1_burstWrite(int slaveAddr, char memAddr, int byteCount, char* data)
{   
    char error;
    
    if (byteCount <= 0)
        return -1;                  /* no write was performed */

    /* send slave address and starting address */
    I2C1->MSA = slaveAddr << 1;
    I2C1->MDR = memAddr;
    I2C1->MCS = 3;                  /* S-(saddr+w)-ACK-maddr-ACK */

    error = I2C_wait_till_done();   /* wait until write is complete */
    if (error) return error;

    /* send data one byte at a time */
    while (byteCount > 1)
    {
        I2C1->MDR = *data++;             /* write the next byte */
        I2C1->MCS = 1;                   /* -data-ACK- */
        error = I2C_wait_till_done();
        if (error) return error;
        byteCount--;
    }
    
    /* send last byte and a STOP */
    I2C1->MDR = *data++;                 /* write the last byte */
    I2C1->MCS = 5;                       /* -data-ACK-P */
    error = I2C_wait_till_done();
    while(I2C1->MCS & 0x40);             /* wait until bus is not busy */
    if (error) return error;

    return 0;       /* no error */
}